﻿using System;
using System.Linq;
using ilgolosone.Shared.Data;
using ilgolosone.Shared.Domain;
using ilgolosone.Shared.Exceptions;
using NHibernate;
using NHibernate.Linq;

namespace ilgolosone.Persistence.NH.Data.Impl
{
    public class NHibernateRepository<TEntity> : RepositoryBase<TEntity> where TEntity : class, IAggregateRoot
    {
        private readonly object _locker = new object();
        private readonly INHibernateUnitOfWork _unitOfWork;

        public NHibernateRepository(INHibernateUnitOfWork unitOfWork)
        {
            if (unitOfWork == null) throw new ArgumentNullException("unitOfWork");
            
            _unitOfWork = unitOfWork;
        }

        protected ISession Session
        {
            get
            {
                if (_unitOfWork.CurrentSession == null)
                {
                    throw new UnitOfWorkNotStartedException();
                }

                return _unitOfWork.CurrentSession;
            }
        }

        protected override IQueryable<TEntity> RepositoryQuery
        {
            get
            {
                lock (_locker)
                {
                    return Session.Linq<TEntity>();
                }
            }
        }

        public override void DeleteAll()
        {
            Session.CreateQuery("delete from " + typeof(TEntity).Name).ExecuteUpdate();
        }

        public override void Dispose()
        {
        }

        public override TEntity Get(Guid id)
        {
            var item = Session.Get<TEntity>(id);

            if (item == null)
            {
                throw new EntityNotFoundException(typeof(TEntity));
            }
            
            return item;
        }

        public override void Save(TEntity item)
        {
            Session.SaveOrUpdate(item);
        }

        public override void Delete(TEntity item)
        {
            Session.Delete(item);
        }
    }
}